package cn.stu.framework.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.stu.common.utils.ApiData;
import cn.stu.common.utils.BeanUtils;
import cn.stu.common.utils.CollUtils;
import cn.stu.common.utils.UserHolder;
import cn.stu.framework.dto.RoleDto;
import cn.stu.framework.entity.Menu;
import cn.stu.framework.entity.Role;
import cn.stu.framework.entity.RoleMenu;
import cn.stu.framework.mapper.MenuMapper;
import cn.stu.framework.mapper.RoleMapper;
import cn.stu.framework.mapper.RoleMenuMapper;
import cn.stu.framework.service.RoleMenuService;
import cn.stu.framework.vo.rolemenu.RightsVo;
import cn.stu.framework.vo.rolemenu.RoleMenuVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 角色菜单服务实施
 *
 * @author 郑志豪
 * @date 2023/09/18
 */
@Service
@AllArgsConstructor
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements RoleMenuService {

    /**
     * 马普
     */
    private RoleMenuMapper mapper;
    /**
     * 角色映射器
     */
    private RoleMapper roleMapper;
    /**
     * 菜单映射器
     */
    private MenuMapper menuMapper;


    /**
     * 角色菜单添加
     *
     * @param add 添加
     * @return {@link ApiData}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "RoleMenuList", allEntries = true)
    public ApiData roleMenuAdd(RoleMenuVo add) {
        if (add.getRoleId() == null) {
            return ApiData.getFalse("角色id为空！");
        }
        LambdaQueryWrapper<Role> roleQuery = new LambdaQueryWrapper<>();
        roleQuery.eq(Role::getRoleId, add.getRoleId());
        boolean roleExists = roleMapper.exists(roleQuery);
        if (!roleExists) {
            return ApiData.getFalse("角色不存在！");
        }
        if (add.getMenuIds() == null) {
            return ApiData.getFalse("未选择菜单");
        }
        List<Long> menuIds = CollUtils.uniqueList(add.getMenuIds());
        LambdaQueryWrapper<Menu> menuQuery = new LambdaQueryWrapper<>();
        menuQuery.in(Menu::getMenuId, menuIds);
        Long menuCount = menuMapper.selectCount(menuQuery);
        if (menuCount != menuIds.size()) {
            return ApiData.getFalse("菜单不存在或不可选择！");
        }
        boolean rmExists = mapper.exists(lambdaQuery().eq(RoleMenu::getRoleId, add.getRoleId()).in(RoleMenu::getMenuId, menuIds).getWrapper());
        if (rmExists) {
            return ApiData.getFalse("不可重复添加权限！");
        }
        List<RoleMenu> addList = menuIds.stream()
                .map(menuId ->
                        {
                            RoleMenu roleMenu = new RoleMenu();
                            roleMenu.setMenuId(menuId);
                            roleMenu.setRoleId(add.getRoleId());
                            return roleMenu;
                        }
                ).collect(Collectors.toList());
        saveBatch(addList);
        //更新时间
        roleTimeUpdate(add.getRoleId());
        return ApiData.getTrue("添加成功！");

    }

    /**
     * 角色菜单更新
     *
     * @param update 更新
     * @return {@link ApiData}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "RoleMenuList", allEntries = true),
            @CacheEvict(value = "routes", key = "'roleId:'+#update.roleId", beforeInvocation = true)
    })
    public ApiData roleMenuUpdate(RoleMenuVo update) {
        if (update.getRoleId() == null) {
            return ApiData.getFalse("角色id为空！");
        }
        if (update.getRoleId() == 1) {
            int count = 0;
            for (Long menuId : update.getMenuIds()) {
                if (menuId == 20 || menuId == 21 || menuId == 23 || menuId == 33) {
                    count++;
                }
            }
            if (count < 4) {
                return ApiData.getFalse("此权限不可更改！");
            }
        }
        Role role = roleMapper.selectById(update.getRoleId());
        if (role == null) {
            return ApiData.getFalse("角色不存在！");
        }
        List<Long> newList = CollUtils.uniqueList(update.getMenuIds());
        if (CollUtil.isEmpty(newList)) {
            //删除原有权限
            LambdaQueryWrapper<RoleMenu> del = new LambdaQueryWrapper<>();
            del.eq(RoleMenu::getRoleId, update.getRoleId());
            mapper.delete(del);
            //更新时间
            roleTimeUpdate(update.getRoleId());
            return ApiData.getTrue("修改成功！");
        }
        LambdaQueryWrapper<Menu> menuQuery = new LambdaQueryWrapper<>();
        menuQuery.in(Menu::getMenuId, newList);
        //查询权限是否存在
        Long menuCount = menuMapper.selectCount(menuQuery);
        if (menuCount != newList.size()) {
            return ApiData.getFalse("菜单不存在或不可选择！");
        }
        //获取当前角色权限
        List<RoleMenu> rmList = lambdaQuery().eq(RoleMenu::getRoleId, role.getRoleId()).list();
        //收集权限ID
        List<Long> oldList = rmList.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        // 找出新增的权限
        List<Long> addedElements = newList.stream()
                .filter(element -> !oldList.contains(element))
                .collect(Collectors.toList());
        // 找出删除的权限
        List<Long> deletedElements = oldList.stream()
                .filter(element -> !newList.contains(element))
                .collect(Collectors.toList());
        //新增权限
        if (CollUtil.isNotEmpty(addedElements)) {
            List<RoleMenu> addList = addedElements.stream()
                    .map(menuId -> new RoleMenu(role.getRoleId(), menuId, role.getRoleName()))
                    .collect(Collectors.toList());
            saveBatch(addList, 100);
        }
        //删除权限
        if (CollUtil.isNotEmpty(deletedElements)) {
            lambdaUpdate().eq(RoleMenu::getRoleId, role.getRoleId()).in(RoleMenu::getMenuId, deletedElements).remove();
        }
        //更新时间
        roleTimeUpdate(update.getRoleId());
        return ApiData.getTrue("修改成功！");
    }

    /**
     * 删除权限
     *
     * @param roleId 角色ID
     * @return {@link ApiData}
     */
    @Override
    @CacheEvict(value = "RoleMenuList", allEntries = true)
    public ApiData roleMenuDel(Long roleId) {
        if (roleId == 1) {
            return ApiData.getFalse("该权限不可清空！");
        }
        boolean exists = mapper.exists(lambdaQuery().eq(RoleMenu::getRoleId, roleId).getWrapper());
        if (!exists) {
            return ApiData.getFalse("参数错误");
        }
        //更新时间
        roleTimeUpdate(roleId);
        lambdaUpdate().eq(RoleMenu::getRoleId, roleId).remove();
        return ApiData.getTrue("删除成功！");
    }

    /**
     * 角色时间更新
     *
     * @param roleId 角色ID
     */
    @Async
    public void roleTimeUpdate(Long roleId) {
        roleMapper.roleUpdateTime(UserHolder.getUser().getUserId(), roleId);
    }

    /**
     * 角色菜单信息
     *
     * @param rmId RM ID
     * @return {@link ApiData}
     */
    @Override
    public ApiData roleMenuInfo(Long rmId) {
        if (rmId == null) {
            return ApiData.getTrue("获取成功", list());
        }
        RoleMenu rm = mapper.selectById(rmId);
        return ApiData.getTrue("获取成功", rm);
    }

    /**
     * 角色菜单列表
     *
     * @param dto DTO
     * @return {@link ApiData}
     */
    @Override
    @Cacheable(value = "RoleMenuList", sync = true)
    public ApiData roleMenuList(RoleDto dto) {
        //查询角色
        LambdaQueryWrapper<Role> roleQuery = new LambdaQueryWrapper<>();
        roleQuery.like(StrUtil.isNotBlank(dto.getRoleName()), Role::getRoleName, dto.getRoleName());
        Page<Role> page = new Page<>(dto.getPage(), dto.getLimit());
        roleMapper.selectPage(page, roleQuery);
        List<Role> list = page.getRecords();
        if (CollUtil.isEmpty(list)) {
            return ApiData.getTrue("获取成功");
        }
        //过滤角色id
        List<Long> roleList = list.stream().map(Role::getRoleId).collect(Collectors.toList());
        //查询权限
        List<RoleMenu> roleMenus = lambdaQuery().in(RoleMenu::getRoleId, roleList).list();
        //根据角色id 对权限分组
        Map<Long, List<Long>> rmByRoleId = roleMenus.stream()
                .collect(Collectors.groupingBy(
                        RoleMenu::getRoleId,
                        Collectors.mapping(RoleMenu::getMenuId, Collectors.toList())));
        List<RightsVo> rightsVos = list.stream()
                .map(role -> {
                    RightsVo rightsVo = BeanUtils.copier(role, RightsVo.class);
                    rightsVo.setMenuIds(rmByRoleId.get(role.getRoleId()));
                    return rightsVo;
                })
                .collect(Collectors.toList());
        return ApiData.getPageTrue("获取成功", page.getTotal(), rightsVos);
    }
}
